(function (angular) {
  'use strict';
  angular.module("fs.waf").run(main);

  main.$inject = ['$rootScope', '$log', '$timeout', '$location', '$state', '$stateParams', '$translate', '$q', '$window', '$ocLazyLoad', '$parse', 'Constants', 'loggerFactory',
    'ajaxServiceFactory', 'storageService', 'StorageConstants', 'modalService', 'commonService', 'routerService', 'ChartJs'];
  function main($rootScope, $log, $timeout, $location, $state, $stateParams, $translate, $q, $window, $ocLazyLoad, $parse, Constants, loggerFactory, ajaxServiceFactory,
    storageService, StorageConstants, modalService, commonService, routerService, ChartJs) {
    var log = loggerFactory.getLogger('fs.waf');
    upgradeLocalStorageData();
    $rootScope.app = {
      color: {},
      settings: {
        theme: Constants.THEME_DEFAULT,
        leftMenu: false,
        logLevel: $log.logLevels['*'],
        collapseLeftMenu: false,
        collapseRightAside: false
      }
    };
    $rootScope.loggerFactory = loggerFactory;
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
    $rootScope.removePageDescription = function () {
      if (angular.isFunction($rootScope.pageDescriptionWtcher)) {
        $rootScope.pageDescriptionWtcher();
      }
      delete $rootScope.pageDescription;
    };
    $rootScope.setPageDescription = function (p) {
      //TODO: change implementation
      /*if ($rootScope.pageDescriptionWatcher) {
        $rootScope.pageDescriptionWatcher();
      }
      if (angular.isFunction(p)) {
        $rootScope.pageDescriptionWtcher = $rootScope.$watch(p, function(description) {
          $rootScope.pageDescription = description;
        });
      } else {
        $rootScope.pageDescription = p;
      }*/
    };
    $rootScope.copyPageIdTooltip = "label.copy.pageid";
    if (!$rootScope.dataType || !$rootScope.dataKey) {
      $rootScope.disabledAuditOrNote = true;
    } else {
      $rootScope.disabledAuditOrNote = false;
    }
    $rootScope.I18N = {
      language: 'en_US'
    };
    $rootScope.setLogLevel = function () {
      loggerFactory.setLevel($rootScope.app.settings.logLevel, '*');
    };
    $rootScope.backTo = function () {
      var state = storageService.getLastHistory() || [];
      var lastUrl = state.fromUrl || [];
      var lastParams = state.fromParams || [];
      if (lastUrl) {
        lastParams._isBack = true;
        $rootScope.go(lastUrl, lastParams);
      }
    };
    $rootScope.go = function (state, params, disableUnloadCheck) {
      if (!state) {
        return;
      }
      var gotoState = function () {
        var toState = routerService.parseState(state);
        var toParams = {
          params: angular.merge(
            {
              __originalState: $state.current.name,
              __state: toState
            },
            params || {}
          )
        };
        if ($rootScope.$uibModalInstance) {
          $rootScope.$uibModalInstance.dismiss();
        }
        $state.go(toState, toParams, {
          location: true,
          // inherit: false,
          reload: toState
        });
      };
      if (disableUnloadCheck) {
        gotoState();
      } else {
        $rootScope.unloadCheck().then(function () {
          gotoState();
        }, angular.noop);
      }
    };
    $rootScope.copySuccess = function () {
      $rootScope.copyPageIdTooltip = "label.copy.copied";
      $timeout(function () {
        $rootScope.copyPageIdTooltip = "label.copy.pageid";
      }, 2000);
    };
    $rootScope.defaultMouseEvent = function ($event) {
      $event.preventDefault();
      $event.stopPropagation();
    };
    //audit
    $rootScope.viewAuditTooltip = "label.audit.viewaudit";
    $rootScope.viewAudit = function () {
      var params = {
        'dataType': $rootScope.dataType,
        'dataKey': $rootScope.dataKey
      };
      modalService.openCustomDialogs({
        'title': 'title.dialogs.auditlistpopup',
        'dialogsModule': 'waf.audit.popuplist',
        'params': params,
        'btnCallback': {
          'ok': function (qaChoiceCtrl) {
          }
        }
      });
    };
    //adminNote
    $rootScope.createNoteTooltip = "label.note.create";
    $rootScope.createNote = function () {
      var dataType = $rootScope.dataType, isForTxn = false, title, dialogsModule, url;
      for (var i = 0; i < Constants.TXN_DATATYPES.length; i++) {
        if (dataType == Constants.TXN_DATATYPES[i]) {
          isForTxn = true;
          break;
        }
      }
      if (!isForTxn) {
        title = 'title.dialogs.adminnote';
        dialogsModule = 'cda.adminNote.popupCreate';
        url = 'do/cda/adminNote/create/submit';
      } else {
        title = 'title.dialogs.txnnote';
        dialogsModule = 'cda.txnNote.popupCreate';
        url = 'do/cda/txnNote/create/submit';
      }
      var params = {
        'dataType': dataType,
        'dataKey': $rootScope.dataKey,
        'dataStatus': $rootScope.dataStatus,
        'serviceCode': $rootScope.serviceCode,
        'taskId': $rootScope.taskId
      };
      modalService.openCustomDialogs({
        'title': title,
        'dialogsModule': dialogsModule,
        'params': params,
        'btnCallback': {
          'ok': function (returnObj) {
            var ajaxService = ajaxServiceFactory.buildAjaxService({
              createSubmit: {
                url: url,
                method: 'post'
              }
            });
            var defer = $q.defer();
            ajaxService.createSubmit(returnObj).then(function (response) {
              defer.resolve(response);
            });
            return defer.promise;
          }
        }
      });
    };
    $rootScope.removeAuditOrNoteParams = function () {
      delete $rootScope.dataType;
      delete $rootScope.dataKey;
      delete $rootScope.dataStatus;
      //delete $rootScope.serviceCode;
      delete $rootScope.taskId;
      $rootScope.disabledAuditOrNote = true;
    };
    $rootScope.saveAuditAndNoteParams = function (toState, toParams) {
      var serviceCode, stateArray, params;
      if (!toState) {
        return;
      }
      stateArray = toState.split('_');
      if (stateArray[1] == 'app') {
        serviceCode = stateArray[2];
      }
      if (toParams && toParams.params) {
        params = toParams.params;
        $rootScope.initAuditOrNoteParams(params.dataType || params.currentDataType, params.dataKey || params.primaryKey, params.dataStatus, serviceCode);
      } else {
        $rootScope.initAuditOrNoteParams('', '', '', serviceCode);
      }
    };
    $rootScope.initAuditOrNoteParams = function (dataType, dataKey, dataStatus, serviceCode, taskId) {
      $rootScope.dataType = dataType;
      $rootScope.dataKey = dataKey;
      $rootScope.dataStatus = dataStatus;
      $rootScope.serviceCode = serviceCode;
      $rootScope.taskId = taskId;
      if (!$rootScope.dataType || !$rootScope.dataKey) {
        $rootScope.disabledAuditOrNote = true;
      } else {
        $rootScope.disabledAuditOrNote = false;
      }
    };
    $rootScope.removeFormState = function () {
      delete $rootScope._isUnloadCheck;
      delete $rootScope._formName;
      delete $rootScope._isUnloadCheck;
      delete $rootScope._formScope;
      delete $rootScope._formDataKey;
      delete $rootScope._formFields;
      delete $rootScope._formDataHashCode;
    };
    $rootScope.initFormState = function (scope, formDataKey, formName) {
      if ($rootScope._formName && $rootScope._formName != formName) {
        return;
      }
      $rootScope._formName = formName;
      if (('mustUnloadCheckForm' != formName && formDataKey.indexOf('.searchCriteria') >= 0) || !scope.fsGridLayoutController || !scope.fsGridLayoutController.fsConfig) {
        return;
      }
      $rootScope._isUnloadCheck = true;
      $rootScope._formName = formName;
      $rootScope._formScope = $rootScope._formScope || {};
      $rootScope._formScope[formDataKey] = scope;
      $rootScope._formDataKey = $rootScope._formDataKey || [];
      $rootScope._formDataKey.push(formDataKey);
      $rootScope._formFields = $rootScope._formFields || [];
      $rootScope._formFields[formDataKey] = $rootScope._formFields[formDataKey] || {};
      $rootScope._formFields[formDataKey] = angular.merge($rootScope._formFields[formDataKey], getPageFormFields(scope.fsGridLayoutController.fsConfig));
      $rootScope._formDataHashCode = $rootScope._formDataHashCode || {};
      $rootScope._formDataHashCode[formDataKey] = commonService.hash(getPageFormData(scope.$eval(formDataKey), $rootScope._formFields[formDataKey]));
      $window.onbeforeunload = isFormChanged;
    };
    $rootScope.initFormTableState = function (scope, tableOptions, formName) {
      if ($rootScope._formName && $rootScope._formName != formName) {
        return;
      }
      if (!tableOptions.data || !angular.isString(tableOptions.data) || !tableOptions.columnDefs) {
        return;
      }
      //fixed issue for open audit then close then click the other menu.
      if (tableOptions.data.indexOf('.searchCriteria') >= 0) {
        return;
      }
      $rootScope._isUnloadCheck = true;
      $rootScope._formName = formName;
      $rootScope._formScope = $rootScope._formScope || {};
      $rootScope._formScope[tableOptions.data] = scope;
      $rootScope._formDataKey = $rootScope._formDataKey || [];
      $rootScope._formDataKey.push(tableOptions.data);
      $rootScope._formFields = $rootScope._formFields || [];
      $rootScope._formFields[tableOptions.data] = getPageFormFields(tableOptions.columnDefs);
      $rootScope._formDataHashCode = $rootScope._formDataHashCode || {};
      $rootScope._formDataHashCode[tableOptions.data] = commonService.hash(getPageFormData(scope.$eval(tableOptions.data), $rootScope._formFields[tableOptions.data]));
      $window.onbeforeunload = isFormChanged;
    };
    $rootScope.disableUnloadCheck = function () {
      delete $rootScope._isUnloadCheck;
      $window.onbeforeunload = null;
    };
    $rootScope.unloadCheck = function () {
      var defer = $q.defer();
      if (!$rootScope._isUnloadCheck || !$rootScope._formScope) {
        $rootScope._isUnloadCheck = true;
        $window.onbeforeunload = isFormChanged;
        defer.resolve(true);
      } else if (hasChanged()) {
        modalService.openConfirmDialogs({
          'messages': ['Are you sure to leave this page?'],
          'btnCallback': {
            'ok': function (response) {
              defer.resolve(true);
            },
            'close': function (response) {
              defer.reject(false);
            }
          }
        });
      } else {
        defer.resolve(true);
      }
      return defer.promise;
    };
    $rootScope.buildAuthService = function (authorizationConfig) {
      var authorizationServices = {};
      angular.forEach(authorizationConfig, function (value, key) {
        authorizationServices[key] = {
          url: 'do/' + value,
          method: 'post'
        };
      });
      return ajaxServiceFactory.buildAjaxService(authorizationServices);
    };
    $rootScope.showLog = function () {
      var logContent = storageService.getLog();
      var logs = [];
      angular.forEach(logContent, function (value, key) {
        this.push(value.content);
      }, logs);
      modalService.openLogDialogs({
        title: 'label.title.log',
        messages: logs.join('\n')
      });
    };
    $rootScope.saveHistory = function (event, toState, toParams, fromState, fromParams) {
      if (toParams.params && toParams.params._isBack) {
        storageService.popHistory();
      }
      if (fromState.name && (!toParams.params || !toParams.params._isBack) && !isIgnoreHistory(fromState)) {
        if (fromParams.params && fromParams.params.isIgnoreHistory) {
          return;
        }
        storageService.saveHistory({
          pageId: $rootScope.pageId,
          fromUrl: fromState.name,
          fromParams: fromParams.params,
          toUrl: toState.name,
          toParams: toParams.params
        });
      }
    };
    $rootScope.loadResource = function (resources) {
      if (resources) {
        storageService.setItemToSession(Constants.SESSION_I18N_RESOURES, resources);
        $rootScope.$emit(Constants.NOTIFY_CHANGE_LANGUAGE);
      }
    };
    $rootScope.collapseLeftMenu = function () {
      $rootScope.app.settings.collapseLeftMenu = !$rootScope.app.settings.collapseLeftMenu
      $rootScope.$broadcast(Constants.COLLPASE_LEFT_MENU);
    };
    $rootScope.$on(Constants.NOTIFY_CHANGE_LANGUAGE, function ($event, param) {
      $event.preventDefault();
      $event.stopPropagation();
      if (param) {
        angular.extend($rootScope.I18N, param);
      }
      if ($rootScope.I18N.language) {
        $translate.use($rootScope.I18N.language).then(function () {
          $translate.refresh($rootScope.I18N.language);
        });
      }
    });
    $rootScope.$on(Constants.NOTIFY_REDIRECT, function ($event, param) {
      $event.preventDefault();
      $event.stopPropagation();
      window.location.href = param.url;
    });
    $rootScope.$on(Constants.NOTIFY_UNAUTHORIZED, function ($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      $rootScope.disableUnloadCheck();
      storageService.clearAllFromSession();
      // storageService.clearAllFromLocal();
      delete $rootScope.user;
      delete $rootScope.site;
      delete $rootScope.menus;
      if (!$stateParams.params || ($stateParams.params.__originalState != 'signon' && $state.$current.name != 'signon')) {
        $rootScope.go('signon');
      }
    });
    $rootScope.$on(Constants.NOTIFY_PAGE_NOT_FOUNT, function ($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      $rootScope.disableUnloadCheck();
      $rootScope.go('waf.error.E404', response);
    });
    $rootScope.$on(Constants.NOTIFY_SYSTEM_ERROR, function ($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      $rootScope.disableUnloadCheck();
      $rootScope.go('waf.error.E500', response.error);
    });
    $rootScope.$on(Constants.NOTIFY_CUSTOMER_ERROR, function ($event, response) {
      $event.preventDefault();
      $event.stopPropagation();
      if (response.error) {
        modalService.openErrorDialogs({
          messages: response.error,
          blocked: true
        });
      }
    });

    ChartJs.Chart.defaults.global.defaultFontFamily = "'Interstate', Arial, sans-serif";
    ChartJs.Chart.scaleService.updateScaleDefaults('linear', {
      ticks: {
        min: 0
      }
    });
    ChartJs.Chart.defaults.global.multiTooltipTemplate = '<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>';
    ChartJs.Chart.defaults.global.tooltips.mode = 'label';
    ChartJs.Chart.defaults.global.elements.line.borderWidth = 1;
    ChartJs.Chart.defaults.global.elements.arc.borderWidth = 1;
    ChartJs.Chart.defaults.global.elements.rectangle.borderWidth = 1;
    ChartJs.Chart.defaults.global.legend.display = false;
    // ChartJs.Chart.defaults.global.elements.line.backgroundColor = 'transparent';

    // write text plugin
    ChartJs.Chart.pluginService.register({
      id: 'drawDoughnutCenterText',
      afterUpdate: function (chartController) {
        var helpers = ChartJs.Chart.helpers, globalConfig, ctx, fontStyle, fontFamily, fontSize, maxFontSize, maxText, datas, center1, center2;
        var centers = chartController.config.options.elements.center;
        if (centers) {
          globalConfig = ChartJs.Chart.defaults.global;
          ctx = chartController.chart.ctx;

          fontStyle = helpers.getValueOrDefault(centers[0].fontStyle, globalConfig.defaultFontStyle);
          fontFamily = helpers.getValueOrDefault(centers[0].fontFamily, globalConfig.defaultFontFamily);

          if (centers[0].fontSize) {
            fontSize = centers[0].fontSize;
          } else {
            // figure out the best font size, if one is not specified
            ctx.save();
            fontSize = helpers.getValueOrDefault(centers[0].minFontSize, 1);
            maxFontSize = helpers.getValueOrDefault(centers[0].maxFontSize, 256);
            maxText = helpers.getValueOrDefault(centers[0].text, centers[0].text);
            do {
              ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
              var textWidth = ctx.measureText(maxText).width;
              if (textWidth < chartController.innerRadius * 2 && fontSize < maxFontSize) {
                fontSize += 1;
              } else {
                fontSize -= 1;
                break;
              }
            } while (true);
            ctx.restore();
          }
          centers[0].font = helpers.fontString(fontSize, fontStyle, fontFamily);
          centers[0].fontSize = fontSize;
          centers[0].fillColor = helpers.getValueOrDefault(centers[0].fontColor, globalConfig.defaultFontColor);

          fontStyle = helpers.getValueOrDefault(centers[1].fontStyle, globalConfig.defaultFontStyle);
          fontFamily = helpers.getValueOrDefault(centers[1].fontFamily, globalConfig.defaultFontFamily);

          if (centers[1].fontSize) {
            fontSize = centers[1].fontSize;
          } else {
            // figure out the best font size, if one is not specified
            ctx.save();
            fontSize = helpers.getValueOrDefault(centers[1].minFontSize, 1);
            maxFontSize = helpers.getValueOrDefault(centers[1].maxFontSize, 256);
            maxText = helpers.getValueOrDefault(centers[1].text, centers[1].text);
            do {
              ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
              var textWidth = ctx.measureText(maxText).width;
              if (textWidth < chartController.innerRadius * 2 && fontSize < maxFontSize) {
                fontSize += 1;
              } else {
                fontSize -= 1;
                break;
              }
            } while (true);
            ctx.restore();
          }
          centers[1].font = helpers.fontString(fontSize, fontStyle, fontFamily);
          centers[1].fontSize = fontSize;
          centers[1].fillColor = helpers.getValueOrDefault(centers[1].fontColor, globalConfig.defaultFontColor);


          chartController.center = {
            center1: centers[0],
            center2: centers[1],
            onClick: chartController.config.options.elements.center.onClick
          }
        }
      },
      beforeDraw: function (chartController) {
        var helpers = ChartJs.Chart.helpers, ctx, config, centerX, centerY, datas, total = 0;
        var centers = chartController.config.options.elements.center;
        if (chartController.center) {
          ctx = chartController.chart.ctx;
          centerX = (chartController.chartArea.left + chartController.chartArea.right) / 2;
          centerY = (chartController.chartArea.top + chartController.chartArea.bottom) / 1.8;
          chartController.center.x = centerX;
          chartController.center.y = centerY;
          ctx.save();
          ctx.textAlign = 'center';
          ctx.textBaseline = 'middle';
          ctx.font = helpers.fontString(chartController.center.center1.fontSize, chartController.center.center1.fontStyle, chartController.center.center1.fontFamily);
          ctx.fillStyle = chartController.center.center1.fillColor;
          ctx.fillText(chartController.center.center1.text, chartController.center.x, centerY - chartController.center.center1.fontSize / 2);
          ctx.font = helpers.fontString(chartController.center.center2.fontSize, chartController.center.center2.fontStyle, chartController.center.center2.fontFamily);
          ctx.fillStyle = chartController.center.center2.fillColor;
          ctx.fillText(chartController.center.center2.text, centerX, centerY + chartController.center.center2.fontSize / 2 + 2);
          ctx.restore();
          if (chartController.center.onClick && !chartController.center.addEventListener) {
            chartController.center.addEventListener = true;
            chartController.chart.canvas.addEventListener("mousemove", function (chartController, config) {
              return function (event) {
                var x, y;
                x = event.layerX;
                y = event.layerY;
                if (x >= (config.x - chartController.innerRadius) && x <= (config.x + chartController.innerRadius) && y <= (config.y + chartController.innerRadius)
                  && y >= (config.y - chartController.innerRadius)) {
                  event.target.parentElement.style.cursor = "pointer";
                  config.inLink = true;
                } else {
                  event.target.parentElement.style.cursor = "";
                  config.inLink = false;
                }
              }
            }(chartController, chartController.center), false);
            chartController.chart.canvas.addEventListener("click", clickHandlerFactory(chartController, chartController.center), false);
          }
        }
        function clickHandlerFactory(chartController, config) {
          return function (event) {
            if (config.inLink) {
              config.onClick(chartController, config, event);
            }
          }
        }
      }
    });

    function getPageFormData(pageModel, fields) {
      var getter, setter, formaData = {};
      if (fields && pageModel) {
        if (angular.isArray(pageModel)) {
          formaData = [];
          angular.forEach(pageModel, function (model, index) {
            formaData[index] = getPageFormData(model, fields);
          });
        } else {
          angular.forEach(fields, function (field, key) {
            getter = $parse(field);
            setter = getter.assign;
            try {
              if (getter(pageModel) !== undefined) {
                setter(formaData, getter(pageModel));
              }
            } catch (e) {
            }
          });
        }
      } else {
        formaData = pageModel;
      }
      return formaData;
    }
    function getPageFormFields(pageConfig) {
      var fields;
      if (!pageConfig) {
        return fields;
      }
      angular.forEach(pageConfig, function (column) {
        if (column.field && (!column.cellTemplate || column.cellTemplate.indexOf('fs-grid-config="row.entity"') != -1)) {
          fields = fields || {};
          fields[column.field] = column.field;
        }
      });
      angular.forEach(pageConfig.gridConfigs, function (grid) {
        if (grid.model) {
          fields = fields || {};
          fields[grid.model] = grid.model;
        }
      });
      angular.forEach(pageConfig.formConfigs, function (form) {
        angular.forEach(form.gridConfigs, function (grid) {
          if (grid.model) {
            fields = fields || {};
            fields[grid.model] = grid.model;
          }
        });
      });
      return fields;
    }
    function isFormChanged($event) {
      if (hasChanged()) {
        ($event || $window.event).returnValue = 'Are you sure to leave this page?';
        return 'Are you sure to leave this page?';
      } else {
        return undefined;
      }
    }
    function hasChanged() {
      var i = 0, scope, dataKey, pageData, fields, changed;
      if (!$rootScope._formDataKey) {
        return false;
      }
      for (i = 0; i < $rootScope._formDataKey.length; i++) {
        dataKey = $rootScope._formDataKey[i];
        scope = $rootScope._formScope[dataKey];
        fields = $rootScope._formFields[dataKey];
        pageData = scope.$eval(dataKey);
        changed = commonService.hash(getPageFormData(pageData, fields)) != $rootScope._formDataHashCode[dataKey];
        if (changed) {
          return changed;
        }
      }
      return false;
    }
    function isIgnoreHistory(state) {
      var pattern = /(?:.*\.(?:create)|(?:createContinue)|(?:createReject)|(?:update)|(?:updateContinue)|(?:updateReject)|(?:delete)|(?:deleteReject))/;
      return pattern.test(state.name);
    }
    function upgradeLocalStorageData() {
      var lastVersionInfo = storageService.getItemFromLocal('SYS_VERSION');
      if (!lastVersionInfo || lastVersionInfo.version != versionInfo.version) {
        // write the logic here when the data of local storage need upgrade
        // storageService.setItemToLocal('SYS_VERSION', versionInfo);
      }
    }

  }
})(angular);